import urllib
import urllib.request
import json
import paho.mqtt.client as mqtt
import struct
import datetime
import time
import ssl
import sys
import threading
import schedule
import serial


global tem
global hum


#修改成自己的即可
DEV_ID = "711598975" #设备ID
PRO_ID = "421469" #产品ID
AUTH_INFO = "qdnr2sLKHjf0=h9pOY=XgTiPBn4="  #APIKEY


TYPE_JSON = 0x01
TYPE_FLOAT = 0x17


def build_payload(type, payload):
    datatype = type
    packet = bytearray()
    packet.extend(struct.pack("!B", datatype))
    if isinstance(payload, str):
        udata = payload.encode('utf-8')
        length = len(udata)
        packet.extend(struct.pack("!H" + str(length) + "s", length, udata))
    return packet

# 当客户端收到来自服务器的CONNACK响应时的回调。也就是申请连接，服务器返回结果是否成功等
def on_connect(client, userdata, flags, rc):
    global tem
    global hum
    print("连接结果:" + mqtt.connack_string(rc))
    #上传数据
    # 定义上传数据的json格式  该格式是oneNET规定好的  按格式修改其中变量即可
    body = {
        "datastreams": [
            {
                "id": "temp",  # 对应OneNet的数据流名称
                "datapoints": [
                    {
                        "value": tem  # 数据值
                    }
                ]
            },
            {
                "id": "hump",  # 对应OneNet的数据流名称
                "datapoints": [
                    {
                        "value": hum  # 数据值
                    }
                ]
            }
        ]
    }
    json_body = json.dumps(body)
    packet = build_payload(TYPE_JSON, json_body)
    client.publish("$dp", packet, qos=1)  #qos代表服务质量



# 从服务器接收发布消息时的回调。
def on_message(client, userdata, msg):
    print("温度:"+str(msg.payload,'utf-8')+"°C")


#当消息已经被发送给中间人，on_publish()回调将会被触发
def on_publish(client, userdata, mid):
    print("mid:" + str(mid))


# 发送和保存传感器数据相关程序  #
def threadDATAPRO(): # 线程数据处理
    threaddatapro = threading.Thread(target=dataCheck)
    threaddatapro.start()
    while True:
        if not threaddatapro.is_alive():  # 如果发送和保存线程卡死 隔60s再次开启
            threaddatapro = threading.Thread(target=dataCheck)
            threaddatapro.start()
        time.sleep(60)


def dataCheck(): # 检测
    global tem
    global hum
    s0=serial.Serial("/dev/ttyAMA0",9600)  # 树莓派端
    # s0=serial.Serial("/dev/ttyUSB1",9600)  # 树莓派USB端
    # s0 = serial.Serial("COM9", 9600)  # PC端

    dataarr = []
    datagdellStage = 0
    charcount = 0
    temp = 0
    while True:
        while s0.inWaiting():
            try:
                temp = s0.read()
            except Exception as e:
                pass

            if datagdellStage == 2 and temp:  # 如果有数据 存到dataarr
                dataarr.append(temp)
                if len(dataarr) >= charcount:
                    print('main line 50 收到的数据：', dataarr)
                    if dataarr[1] == b'a':
                        tem = dataarr[6][0] + dataarr[7][0]*0.1
                        hum = dataarr[8][0] + dataarr[9][0]*0.1
            if datagdellStage == 1 and temp:  # 如果有数据
                if temp == b'a':   # data:
                    datagdellStage = 2
                    charcount = 10
                    dataarr.append(temp)
                    pass
                if datagdellStage != 2:
                    datagdellStage = 0
                    charcount = 0
                    dataarr = []
                    temp = '\x00'
            if temp == b'd':  # 收到帧头
                datagdellStage = 1
                charcount = 0
                dataarr = []
                dataarr.append(temp)
        time.sleep(0.01)



if __name__ == '__main__':
    global tem
    global hum

    tem = 0
    hum = 0

    threadDataPro = threading.Thread(target=threadDATAPRO)
    threadDataPro.setDaemon(True)  # 守护线程
    threadDataPro.start()

    client = mqtt.Client(client_id=DEV_ID, protocol=mqtt.MQTTv311)
    client.on_connect = on_connect
    client.on_publish = on_publish
    client.on_message = on_message
    client.username_pw_set(username=PRO_ID, password=AUTH_INFO)
    client.connect('183.230.40.39', port=6002, keepalive=120)

    # client.loop_forever()
    client.loop_start()

    # schedule.every(3).seconds.do(dataSend)  # 每几秒发送一次数据
    while True:
        #schedule.run_pending() #定时器,在while True死循环中，schedule.run_pending()是保持schedule一直运行，
        # 去查询上面那一堆的任务，在任务中，就可以设置不同的时间去运行
        # 定义上传数据的json格式  该格式是oneNET规定好的  按格式修改其中变量即可
        body = {
            "datastreams": [
                {
                    "id": "temp",  # 对应OneNet的数据流名称
                    "datapoints": [
                        {
                            "value": tem  # 数据值
                        }
                    ]
                },
                {
                    "id": "hump",  # 对应OneNet的数据流名称
                    "datapoints": [
                        {
                            "value": hum  # 数据值
                        }
                    ]
                }
            ]
        }
        json_body = json.dumps(body)
        packet = build_payload(TYPE_JSON, json_body)
        client.publish("$dp", packet, 1)
        time.sleep(3)

